package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.audit.aliyun.GreenImageScan;
import com.heima.audit.aliyun.GreenTextScan;
import com.heima.audit.baidu.BaiduImageScan;
import com.heima.audit.baidu.BaiduTextScan;
import com.heima.audit.tess4j.Tess4jClient;
import com.heima.common.redis.CacheService;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.service.*;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WmNewsAuditServiceImpl implements WmNewsAuditService {

    @Autowired
    private WmNewsService wmNewsService;

    @Autowired
    private WmNewsTaskService taskService;


    @Override
    /**
     * 自媒体文章自动审核
     * @param wmNews
     * @param contentImageList
     * @return
     */
    @Async("taskExecutor")
    public void auditWmNews(WmNews wmNews, List<String> contentImageList) {
        System.out.println("auditWmNews:当前线程:"+Thread.currentThread().getId());
        //第一部分：准备文章的全部文本和全部图片地址
        //1.1 抽取全部文本
        String text = extractText(wmNews);

        //1.2 找到全部的图片地址
        String imageStr = wmNews.getImages();
        List<String> coverImageList = new ArrayList<>();
        if(StringUtils.isNotBlank(imageStr)){
            String[] imageArr = imageStr.split(",");
            coverImageList = Arrays.asList(imageArr); //封面图片地址列表
        }

        //全部图片地址去重集合
        Set<String> allImageSet = new HashSet<>();
        allImageSet.addAll(contentImageList);
        allImageSet.addAll(coverImageList);

        String ocrText = "";   //ocrText(allImageSet);

        if(StringUtils.isNotBlank(ocrText)){
            text = text + ocrText;
        }

        //使用DFA对文本内容进行审核
        boolean flag = true;  // dfaAudit(wmNews, text);
        if(!flag){
            log.error("[自媒体文章自动审核]DFA文本审核失败，文章id:{}", wmNews.getId());
            return;
        }

        //第二部分：调用百度云文本检测接口进行审核
        flag = true;   // textAudit(wmNews, text);
        if(!flag){
            log.error("[自媒体文章自动审核]百度云文本审核失败或不确定，文章id:{}", wmNews.getId());
            return;
        }

        //第三部分：调用用百度云图片检测接口进行审核
        flag = true;  // imageAudit(wmNews, allImageSet);
        if(!flag){
            log.error("[自媒体文章自动审核]百度云图片审核失败或不确定，文章id:{}", wmNews.getId());
            return;
        }


        //第四部分：根据发布时间决定是否创建APP文章
        //如果发布时间大于系统当前时间，则设置文章状态为自动审核通过，不创建APP文章
        if(wmNews.getPublishTime().getTime()>System.currentTimeMillis()){
            wmNews.setStatus(WmNews.Status.SUCCESS.getCode());//自动审核通过，待发布
            wmNews.setReason("自动审核通过，待发布");
            wmNewsService.updateById(wmNews);

            //将未来待发布文章当作任务添加到DB和REDIS延迟队列中
            //  发布延迟任务到MQ
            //taskService.addTask(wmNews);


        } else { //如果发布时间小于等于系统当前时间，则创建APP文章且设置文章状态为已发布
            wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());//已发布
            wmNews.setReason("审核通过已发布");
            wmNewsService.updateById(wmNews);

            //调用feign接口创建或更新APP文章信息
            saveApArticle(wmNews);
        }

    }

    @Autowired
    private Tess4jClient tess4jClient;

    /**
     * OCR识别全部图片中的文本
     * @param allImageSet
     * @return
     */
    private String ocrText(Set<String> allImageSet) {
        StringBuffer text = new StringBuffer();
        for (String url : allImageSet) {
            byte[] bytes = fileStorageService.downLoadFile(url);

            //从byte[]转换为butteredImage
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
            try {
                BufferedImage imageFile = ImageIO.read(in);
                //识别图片的文字
                String result = tess4jClient.doOCR(imageFile);
                text.append(result);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TesseractException e) {
                e.printStackTrace();
            }
        }
        return text.toString();
    }

    @Autowired
    private WmSensitiveService sensitiveService;

    @Autowired
    private CacheService cacheService;

    /**
     * DFA本地敏感词库审核
     * @param wmNews
     * @param text
     * @return
     */
    private boolean dfaAudit(WmNews wmNews, String text) {
        boolean flag = true; //默认审核通过
        //1.查询全部敏感词数据

        //1.1 先从Redis缓存中查询敏感词列表
        String key = "sensitive:cache:list";
        List<String> sensitiveStrList = cacheService.lRange(key, 0, -1);
        if(sensitiveStrList.isEmpty()){
            //1.2 如果查询不到，再从数据库表查询，设置到Redis缓存中
            List<WmSensitive> sensitiveList = sensitiveService.list(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
            sensitiveStrList = sensitiveList.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

            cacheService.lLeftPushAll(key,sensitiveStrList);
        }

        //2.将敏感词初始化到DFA词库中
        SensitiveWordUtil.initMap(sensitiveStrList);

        //3.将文本拿到DFA词库中进行匹配得到MAP
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);

        //4.根据MAP结果处理
        if(map.size()>0){
            wmNews.setStatus(WmNews.Status.FAIL.getCode()); //设置文章状态为审核失败
            wmNews.setReason("DFA文本审核失败");
            wmNewsService.updateById(wmNews);

            flag = false;
        }
        return flag;
    }

    @Autowired
    private IArticleClient articleClient;

    @Autowired
    private WmChannelService wmChannelService;

    @Autowired
    private WmUserService wmUserService;

    /**
     * 创建或更新APP文章
     * @param wmNews
     * @return
     */
    public void saveApArticle(WmNews wmNews) {
        //1.构建dto数据
        ArticleDto dto = new ArticleDto();
        dto.setId(wmNews.getArticleId()); //APP文章ID
        dto.setTitle(wmNews.getTitle()); //标题
        dto.setContent(wmNews.getContent()); //内容
        dto.setLabels(wmNews.getLabels()); //标签
        dto.setLayout(wmNews.getType()); //布局方式
        dto.setImages(wmNews.getImages());//封面图片
        dto.setPublishTime(wmNews.getPublishTime());//发布时间
        if(wmNews.getArticleId()==null){
            dto.setCreatedTime(new Date());
        }
        dto.setChannelId(wmNews.getChannelId());//频道ID
        WmChannel wmChannel = wmChannelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());//频道名称

        //查询自媒体用户
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId()==null?0:wmUser.getApAuthorId().longValue());
        dto.setAuthorName(wmUser.getName());


        //2.调用feign接口保存或修改APP文章
        ResponseResult responseResult = articleClient.saveArticle(dto);
        if(responseResult.getCode()!=200){
            log.error("[自媒体文章自动审核]创建APP文章数据失败，文章id:{}", wmNews.getId());
        }

        //3.得到响应里的articleId，更新到wmNews表中
        Long articleId = Long.valueOf(responseResult.getData()+"");
        wmNews.setArticleId(articleId);//APP文章ID
        wmNewsService.updateById(wmNews);
    }

//    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;

    /**
     * 使用阿里云内容安全接口审核图片
     * @param wmNews
     * @param allImageSet
     * @return
     */
    private boolean imageAudit(WmNews wmNews, Set<String> allImageSet) {
        boolean flag = true;//默认审核通过
        //1.下载所有图片，得到字节数组列表
        List<byte[]> imageBytesList = new ArrayList<>();
        for (String url : allImageSet) {
            byte[] imageBytes = fileStorageService.downLoadFile(url);
            imageBytesList.add(imageBytes);
        }

        //2. 调用内容安全接口审核图片
        try {
            Map<String,String> map = greenImageScan.imageScan(imageBytesList);
            String suggestion = map.get("suggestion");
            //3. 根据结果处理
            if(suggestion.equals("block")){
                flag = false;
                wmNews.setStatus(WmNews.Status.FAIL.getCode()); //设置文章状态为审核失败
                wmNews.setReason("阿里云图片审核失败");
                wmNewsService.updateById(wmNews);
            } else if(suggestion.equals("review")){
                flag = false;
                wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode()); //设置文章状态为待人工审核
                wmNews.setReason("阿里云图片审核不确定，进入人工审核");
                wmNewsService.updateById(wmNews);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

//    @Autowired
    private GreenTextScan greenTextScan;

//    @Autowired
//    private BaiduTextScan baiduTextScan;
//
//    @Autowired
//    private BaiduImageScan baiduImageScan;

    /**
     * 使用阿里云内容安全接口审核文本
     * @param wmNews
     * @param text
     * @return
     */
    private boolean textAudit(WmNews wmNews, String text) {
        boolean flag = true; //默认审核通过
        try {

            Map<String,String> map = greenTextScan.greeTextScan(text);
            String suggestion = map.get("suggestion");
            if(suggestion.equals("block")){
                flag = false;
                wmNews.setStatus(WmNews.Status.FAIL.getCode()); //设置文章状态为审核失败
                wmNews.setReason("阿里云文本审核失败");
                wmNewsService.updateById(wmNews);
            } else if(suggestion.equals("review")){
                flag = false;
                wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode()); //设置文章状态为待人工审核
                wmNews.setReason("阿里云文本审核不确定，进入人工审核");
                wmNewsService.updateById(wmNews);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 抽取文章中全部的文本
     * @param wmNews
     * @return
     */
    private String extractText(WmNews wmNews) {
        //文本来源： 标题 + 标签 + 内容文本
        StringBuffer text = new StringBuffer();
        text.append(wmNews.getTitle());//标题
        text.append(wmNews.getLabels());//标签
        if(StringUtils.isNotBlank(wmNews.getContent())){
            List<Map> mapList = JSON.parseArray(wmNews.getContent(), Map.class);
            if(mapList!=null && mapList.size()>0){
                for (Map<String,String> map : mapList) {
                    String type = map.get("type");
                    if(type.equals("text")){
                        String contentText = map.get("value");
                        text.append(contentText);//内容文本
                    }
                }
            }
        }
        return text.toString();
    }
}
